package com.jevons.muffin.vm;

import android.app.Activity;
import android.content.Intent;

import androidx.databinding.Observable;
import androidx.databinding.PropertyChangeRegistry;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import com.jevons.muffin.event.BaseActionEvent;
import com.jevons.muffin.event.FinishActivityEvent;
import com.jevons.muffin.event.LoadingDialogEvent;
import com.jevons.muffin.event.StartActivityEvent;
import com.jevons.muffin.event.ToastEvent;

import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;

/**
 * 基类
 * @auth linaisheng
 * Created on 2021/6/29.
 * Description：
 */
public class BaseViewModel extends ViewModel implements IViewModelAction, Observable {

    private PropertyChangeRegistry callbacks = new PropertyChangeRegistry();

    protected final MutableLiveData<BaseActionEvent> actionLiveData;

    protected LifecycleOwner lifecycleOwner;
    //管理RxJava，主要针对RxJava异步操作造成的内存泄漏
    private CompositeDisposable mCompositeDisposable;


    public BaseViewModel() {
        actionLiveData = new MutableLiveData<>();
        mCompositeDisposable = new CompositeDisposable();
    }

    /**
     * 将 {@link Disposable} 添加到 {@link CompositeDisposable} 中统一管理
     * 可在 {@link Activity#onDestroy()} 中使用 {@link #unDispose()} 停止正在执行的 RxJava 任务,避免内存泄漏
     * 目前框架已使用 {@link RxLifecycle} 避免内存泄漏,此方法作为备用方案
     *
     * @param disposable
     */
    protected void addSubscribe(Disposable disposable) {
        if (mCompositeDisposable == null) {
            mCompositeDisposable = new CompositeDisposable();
        }
        mCompositeDisposable.add(disposable);
    }

    /**
     * 停止集合中正在执行的 RxJava 任务
     */
    public void unDispose() {
        if (mCompositeDisposable != null) {
            mCompositeDisposable.clear();//保证 Activity 结束时取消所有正在执行的订阅
        }
    }

    @Override
    public void showLoading() {
        showLoading(null);
    }

    @Override
    public void showLoading(boolean isCanBack) {
        actionLiveData.setValue(BaseActionEvent.create(
                new LoadingDialogEvent(null, isCanBack)));
    }

    @Override
    public void showLoading(String message) {
        actionLiveData.setValue(BaseActionEvent.create(
                new LoadingDialogEvent(message)));
    }

    @Override
    public void showLoading(String message, boolean isCanBack) {
        actionLiveData.setValue(BaseActionEvent.create(
                new LoadingDialogEvent(message, isCanBack)));
    }

    @Override
    public void hideLoading() {
        actionLiveData.setValue(BaseActionEvent.create(
                new LoadingDialogEvent(false)));
    }

    @Override
    public void showToast(String message) {
        actionLiveData.setValue(BaseActionEvent.create(
                new ToastEvent(message)));
    }

    @Override
    public void finish() {
        actionLiveData.setValue(BaseActionEvent.create(
                new FinishActivityEvent()));
    }

    @Override
    public void finishWithResultOk() {
        actionLiveData.setValue(BaseActionEvent.create(
                new FinishActivityEvent(Activity.RESULT_OK)));
    }

    @Override
    public void startActivity(Class clz) {
        actionLiveData.setValue(BaseActionEvent.create(
                new StartActivityEvent(clz)));
    }

    @Override
    public void startActivity(Intent intent) {
        actionLiveData.setValue(BaseActionEvent.create(
                new StartActivityEvent(intent)));
    }

    @Override
    public void startActivity(Intent intent, boolean isFinishActivity) {
        actionLiveData.setValue(BaseActionEvent.create(
                new StartActivityEvent(intent, isFinishActivity)));
    }

    @Override
    public MutableLiveData<BaseActionEvent> getActionLiveData() {
        return actionLiveData;
    }

    public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
        this.lifecycleOwner = lifecycleOwner;
    }

    @Override
    public void addOnPropertyChangedCallback(
            Observable.OnPropertyChangedCallback callback) {
        callbacks.add(callback);
    }


    @Override
    public void removeOnPropertyChangedCallback(
            Observable.OnPropertyChangedCallback callback) {
        callbacks.remove(callback);
    }


    /**
     * Notifies observers that all properties of this instance have changed.
     */
    protected void notifyChange() {
        callbacks.notifyCallbacks(this, 0, null);
    }

    /**
     * Notifies observers that a specific property has changed. The getter for the
     * property that changes should be marked with the @Bindable annotation to
     * generate a field in the BR class to be used as the fieldId parameter.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    protected void notifyPropertyChanged(int fieldId) {
        callbacks.notifyCallbacks(this, fieldId, null);
    }

}
